#include "znx_http_headers.h"


void
znx_http_headers_add(znx_http_headers_t *headers, znx_http_header_t *header)
{
    znx_queue_insert_tail(&headers->head, &header->queue);

    if (header->name.crc == 0) {
        header->name.crc = znx_crc32_long_lower(header->name.data, header->name.len);
    }

    uint32_t idx = header->name.crc % ZNX_HTTP_HEADER_HASH_SLOT;
    znx_queue_t *hash_list = &headers->hash_lists[idx];
    znx_queue_insert_tail(hash_list, &header->queue_in_hash);
}


void
znx_http_headers_set(znx_http_headers_t *headers, znx_http_header_t *header)
{
    znx_http_header_t       *tmp_header;
    znx_http_header_t       *match_header = NULL;
    znx_queue_t             *q;

    if (header->name.crc == 0) {
        header->name.crc = znx_crc32_long_lower(header->name.data, header->name.len);
    }

    uint32_t idx = header->name.crc % ZNX_HTTP_HEADER_HASH_SLOT;
    znx_queue_t *hash_list = &headers->hash_lists[idx];

    q = znx_queue_head(hash_list);
    while (q != hash_list) {
        tmp_header = znx_queue_data(q, znx_http_header_t, queue_in_hash);
        q = q->next;

        if (headers->cmp_handle(&header->name, &tmp_header->name) == 0) {
            if (!match_header) {
                match_header = tmp_header;
                continue;
            }
            znx_queue_remove(&tmp_header->queue);
            znx_queue_remove(&tmp_header->queue_in_hash);
            znx_queue_insert_tail(&headers->free_head, &tmp_header->queue);
        }
    }

    if (match_header) {
        match_header->val = header->val;
        return;
    }

    znx_queue_insert_tail(&headers->head, &header->queue);
    znx_queue_insert_tail(hash_list, &header->queue_in_hash);
}


znx_http_header_t *
znx_http_headers_get(znx_http_headers_t *headers,
    znx_http_header_name_t *name, size_t index)
{
    znx_http_header_t   *tmp_header;
    znx_queue_t         *q;
    size_t              i = 0;

    if (index < 0) {
        index = 0;
    }

    if (name->crc == 0) {
        name->crc = znx_crc32_long_lower(name->data, name->len);
    }

    uint32_t idx = name->crc % ZNX_HTTP_HEADER_HASH_SLOT;
    znx_queue_t *hash_list = &headers->hash_lists[idx];

    q = znx_queue_head(hash_list);
    while (q != hash_list) {
        tmp_header = znx_queue_data(q, znx_http_header_t, queue_in_hash);
        q = q->next;

        if (headers->cmp_handle(name, &tmp_header->name) == 0) {
            if (i == index) {
                return tmp_header;
            }
            i++;
        }
    }

    return NULL;
}


void
znx_http_headers_del_once(znx_http_headers_t *headers,
    znx_http_header_name_t *name)
{
    znx_http_header_t   *tmp_header;
    znx_queue_t         *q;

    if (name->crc == 0) {
        name->crc = znx_crc32_long_lower(name->data, name->len);
    }

    uint32_t idx = name->crc % ZNX_HTTP_HEADER_HASH_SLOT;
    znx_queue_t *hash_list = &headers->hash_lists[idx];

    q = znx_queue_head(hash_list);
    while (q != hash_list) {
        tmp_header = znx_queue_data(q, znx_http_header_t, queue_in_hash);
        q = q->next;
        if (headers->cmp_handle(name, &tmp_header->name) == 0) {
            znx_queue_remove(&tmp_header->queue);
            znx_queue_remove(&tmp_header->queue_in_hash);
            znx_queue_insert_tail(&headers->free_head, &tmp_header->queue);
            return;
        }
    }
}


void
znx_http_headers_del(znx_http_headers_t *headers,
    znx_http_header_name_t *name)
{
    znx_http_header_t   *tmp_header;
    znx_queue_t         *q;

    if (name->crc == 0) {
        name->crc = znx_crc32_long_lower(name->data, name->len);
    }

    uint32_t idx = name->crc % ZNX_HTTP_HEADER_HASH_SLOT;
    znx_queue_t *hash_list = &headers->hash_lists[idx];

    q = znx_queue_head(hash_list);
    while (q != hash_list) {
        tmp_header = znx_queue_data(q, znx_http_header_t, queue_in_hash);
        q = q->next;
        if (headers->cmp_handle(name, &tmp_header->name) == 0) {
            znx_queue_remove(&tmp_header->queue);
            znx_queue_remove(&tmp_header->queue_in_hash);
            znx_queue_insert_tail(&headers->free_head, &tmp_header->queue);
        }
    }
}


znx_http_header_t *
znx_http_headers_get_free_hader(znx_http_headers_t *headers)
{
    znx_queue_t         *q;
    znx_http_header_t   *tmp_header;

    q = znx_queue_head(&headers->free_head);
    if (q == &headers->free_head) {
        return NULL;
    }

    znx_queue_remove(q);
    tmp_header = znx_queue_data(q, znx_http_header_t, queue);

    return tmp_header;
}

